import tkinter as tk
from tkinter import ttk


class App(tk.Tk):
    """主应用类，作为全局控制器"""

    def __init__(self):
        super().__init__()
        self.title("动态类型交互示例")
        self.geometry("400x300")
        self.user_data = {"username": "guest", "theme": "light"}  # 主应用数据

        # 初始化样式
        self.setup_styles()

        # 创建主框架和页面
        self.main_frame = ttk.Frame(self)
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 创建页面并传递自身作为控制器
        self.page = SamplePage(self.main_frame, self)
        self.page.frame.pack(fill=tk.BOTH, expand=True)

    def setup_styles(self):
        """设置ttk样式"""
        style = ttk.Style()
        # 亮色主题样式
        style.configure("Light.TFrame", background="#f0f0f0")
        style.configure("Light.TLabel", foreground="black")
        style.configure("Light.TRadiobutton", foreground="black")
        style.configure("Light.TButton", foreground="black")

        # 暗色主题样式
        style.configure("Dark.TFrame", background="#333")
        style.configure("Dark.TLabel", foreground="white")
        style.configure("Dark.TRadiobutton", foreground="white")
        style.configure("Dark.TButton", foreground="white")

    def update_user_data(self, key, value):
        """主应用的控制器方法：更新用户数据"""
        self.user_data[key] = value
        self.update_title()

    def update_title(self):
        """主应用的控制器方法：根据数据更新窗口标题"""
        username = self.user_data["username"]
        theme = self.user_data["theme"]
        self.title(f"用户: {username} | 主题: {theme}")

    def get_user_theme(self):
        """主应用的控制器方法：获取用户主题"""
        return self.user_data["theme"]


class BasePage:
    """页面基类，通过controller参数与主应用交互"""

    def __init__(self, parent, controller):
        """ 
            parent: 父容器（通常是主应用的Frame）
            controller: 主应用的控制器（App实例）
        """
        self.controller = controller  # 动态类型的controller参数
        self.frame = ttk.Frame(parent)

        # 动态调用controller的方法（无需提前声明类型）
        self.current_theme = controller.get_user_theme()
        self.configure_theme()  # 调用主题配置方法

    def configure_theme(self):
        """配置主题的基类方法（可在子类中重写）"""
        pass  # 基类中提供空实现，避免子类未实现时报错


class SamplePage(BasePage):
    """具体页面类，演示controller参数的使用"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        # 创建页面控件，指定样式前缀
        self.frame = ttk.Frame(parent, style=f"{self.current_theme}.TFrame")

        # 创建页面控件
        ttk.Label(
            self.frame, text="用户名:", style=f"{self.current_theme}.TLabel"
        ).pack(pady=5, anchor=tk.W)
        self.username_entry = ttk.Entry(self.frame)
        self.username_entry.pack(fill=tk.X, padx=5, pady=5)
        self.username_entry.insert(
            0, controller.user_data["username"]
        )  # 直接访问controller的数据

        ttk.Label(self.frame, text="主题:", style=f"{self.current_theme}.TLabel").pack(
            pady=5, anchor=tk.W
        )
        theme_frame = ttk.Frame(self.frame, style=f"{self.current_theme}.TFrame")
        theme_frame.pack(fill=tk.X, padx=5, pady=5)

        self.light_rb = ttk.Radiobutton(
            theme_frame,
            text="亮色",
            value="light",
            command=lambda: self.change_theme("light"),
            style=f"{self.current_theme}.TRadiobutton",
        )
        self.dark_rb = ttk.Radiobutton(
            theme_frame,
            text="暗色",
            value="dark",
            command=lambda: self.change_theme("dark"),
            style=f"{self.current_theme}.TRadiobutton",
        )
        self.light_rb.pack(side=tk.LEFT)
        self.dark_rb.pack(side=tk.LEFT)

        # 初始化主题选择
        if self.current_theme == "dark":
            self.dark_rb.invoke()

        # 应用按钮
        ttk.Button(
            self.frame,
            text="应用设置",
            command=self.apply_settings,
            style=f"{self.current_theme}.TButton",
        ).pack(pady=10)

    def change_theme(self, theme):
        """修改主题（通过controller更新主应用数据）"""
        self.controller.update_user_data("theme", theme)
        self.configure_theme()  # 主题变更后更新界面

    def apply_settings(self):
        """应用设置：从视图获取数据，通过controller更新主应用"""
        username = self.username_entry.get()
        if username:
            self.controller.update_user_data("username", username)

    def configure_theme(self):
        """配置主题的子类实现"""
        theme = self.controller.get_user_theme()
        # 销毁旧框架，创建新框架（ttk样式变更需重建控件）
        self.frame.destroy()
        self.frame = ttk.Frame(self.controller.main_frame, style=f"{theme}.TFrame")
        self.frame.pack(fill=tk.BOTH, expand=True)

        # 重新创建所有控件并应用新样式
        ttk.Label(self.frame, text="用户名:", style=f"{theme}.TLabel").pack(
            pady=5, anchor=tk.W
        )
        self.username_entry = ttk.Entry(self.frame)
        self.username_entry.pack(fill=tk.X, padx=5, pady=5)
        self.username_entry.insert(0, self.controller.user_data["username"])

        ttk.Label(self.frame, text="主题:", style=f"{theme}.TLabel").pack(
            pady=5, anchor=tk.W
        )
        theme_frame = ttk.Frame(self.frame, style=f"{theme}.TFrame")
        theme_frame.pack(fill=tk.X, padx=5, pady=5)

        self.light_rb = ttk.Radiobutton(
            theme_frame,
            text="亮色",
            value="light",
            command=lambda: self.change_theme("light"),
            style=f"{theme}.TRadiobutton",
        )
        self.dark_rb = ttk.Radiobutton(
            theme_frame,
            text="暗色",
            value="dark",
            command=lambda: self.change_theme("dark"),
            style=f"{theme}.TRadiobutton",
        )
        self.light_rb.pack(side=tk.LEFT)
        self.dark_rb.pack(side=tk.LEFT)

        if theme == "dark":
            self.dark_rb.invoke()

        ttk.Button(
            self.frame,
            text="应用设置",
            command=self.apply_settings,
            style=f"{theme}.TButton",
        ).pack(pady=10)


if __name__ == "__main__":
    app = App()
    app.mainloop()